#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "shm.h"
#include <dsystem/funcs.h>
#ifdef DMALLOC
#include <imp/dmalloc.h>
#endif
#define FUNC_NAME_SIZE 20
#define FUNC_NUM 30

#define DP_INFO(...) { printf("info: %s,%d", __func__, __LINE__); printf(__VA_ARGS__); }
#define DP_WARN(...) { printf("warn: %s,%d", __func__, __LINE__); printf(__VA_ARGS__); }
#define DP_ERR(...) { printf("err: %s,%d ", __func__, __LINE__); printf(__VA_ARGS__); }


typedef struct {
	int used;
	char name[FUNC_NAME_SIZE];
	/* case 1 , use debug system mem*/
	int (*cb_smem)(void *buf, int msize, void **pri);
	/* case 2 , use user mem*/
	int (*cb_umem)(umem_info *uinfo, void **pri);
	int (*cb_umem_end)(void **pri);

	/* update everytime cb return */
	void *pri;
	/* used internal*/
	struct {
		umem_info uinfo;
		int notend;
		void *pos;
	}state;
} func_attr;

func_attr funcs[FUNC_MODULE_END][FUNC_NUM];

int func_dispatch(void *buf, int msize);
int func_init(void)
{
	int ret = -1;
	ret = shm_init();
	if (0 != ret) {
		DP_ERR("shm_init error\n");
		return 0;
	}
	ret = shm_register_cb(func_dispatch);
	if (0 != ret) {
		shm_deinit();
		DP_ERR("shm_init error\n");
		return 0;
	}
	memset(funcs, sizeof(funcs), 0);
	return 0;
}

void func_deinit(void)
{
	shm_deinit();
}

int dsys_func_share_mem_register(int mid, int fid, char *name, int (*cb_smem)(void *buf, int msize, void **pri))
{
	func_attr *fa;
	if ((mid < FUNC_MODULE_ISP) || (mid >= FUNC_MODULE_END)) {
		DP_ERR("mid = %d\n", mid);
		return -1;
	}
	if ((fid < 0) || (fid >= FUNC_NUM)) {
		DP_ERR("fid = %d\n", fid);
		return -1;
	}
	fa = &funcs[mid][fid];
	if (0 == fa->used) {
		fa->used = 1;
		fa->cb_smem = cb_smem;
		memcpy(fa->name, name, (strlen(name)<FUNC_NAME_SIZE)?strlen(name):FUNC_NAME_SIZE);
	} else {
		DP_WARN("fid register already name = %s\n", fa->name);
	}
	return 0;
}

int dsys_func_user_mem_register(int mid, int fid, char *name, int (*cb_umem)(umem_info *uinfo, void **pri), int (*cb_umem_end)(void **pri))
{
	func_attr *fa;
	if ((mid < FUNC_MODULE_ISP) || (mid >= FUNC_MODULE_END)) {
		DP_ERR("mid = %d\n", mid);
		return -1;
	}
	if ((fid < 0) || (fid >= FUNC_NUM)) {
		DP_ERR("fid = %d\n", fid);
		return -1;
	}
	fa = &funcs[mid][fid];
	if (0 == fa->used) {
		fa->used = 1;
		fa->cb_umem = cb_umem;
		fa->cb_umem_end = cb_umem_end;
		memcpy(fa->name, name, (strlen(name)<FUNC_NAME_SIZE)?strlen(name):FUNC_NAME_SIZE);
	} else {
		DP_ERR("fid register already name = %s\n", fa->name);
		return -1;
	}
	return 0;
}
int dsys_func_unregister(int mid, int fid)
{
	func_attr *fa;
	if ((mid < FUNC_MODULE_ISP) || (mid >= FUNC_MODULE_END)) {
		DP_ERR("mid = %d\n", mid);
		return -1;
	}
	if ((fid < 0) || (fid >= FUNC_NUM)) {
		DP_ERR("fid = %d\n", fid);
		return -1;
	}
	fa = &funcs[mid][fid];
	if (0 == fa->used) {
		DP_WARN(" fid unregister already mid:fid=%d:%d\n", mid, fid);
	} else {
		if (NULL != fa->pri) {
			DP_WARN("pri do not free\n");
			free(fa->pri);
		}
		memset(fa, 0, sizeof(fa));
		return 0;
	}
	return 0;
}


int func_dispatch(void *buf, int msize)
{
	int ret = -1;
	int mid = -1;
	int fid = -1;
	int smem = 0;

	dformat *df = buf;
	mid = df->mid;
	fid = df->fid;
	if ((mid < FUNC_MODULE_ISP) || (mid >= FUNC_MODULE_END)) {
		DP_ERR("mid = %d\n", mid);
		df->out.ret = -1;
		return -1;
	}
	if ((fid < 0) || (fid >= FUNC_NUM)) {
		DP_ERR("fid = %d\n", fid);
		df->out.ret = -1;
		return -1;
	}
	if ((0 == funcs[mid][fid].used)) {
		DP_ERR("used= %d\n", funcs[mid][fid].used);
		df->out.ret = -1;
		return -1;
	}
	if ((NULL != funcs[mid][fid].cb_smem)) {
		smem = 1;
	} else if ((NULL != funcs[mid][fid].cb_umem)) {
		smem = 0;
	} else {
		DP_ERR("func mid:fid:used:cb= %d:%d:%d:%p\n", mid, fid, funcs[mid][fid].used, funcs[mid][fid].cb_smem);
		df->out.ret = -1;
		return -1;
	}
	if (FUNC_FLAG_DBG & df->flg) {
		DP_INFO("func mid:fid:name= %d:%d:%s\n", mid, fid, funcs[mid][fid].name);
	}

	func_attr *fa = &funcs[mid][fid];

	if (1 == smem) {
		ret = fa->cb_smem(buf, msize, &fa->pri);
		if (-1 == ret) {
			DP_ERR("func mid:fid:name= %d:%d:%s\n", mid, fid, fa->name);
			df->out.ret = -1;
			return -1;
		}
	/* states of once umem */
	} else {
		dformat *df = buf;
		int max = msize - ((unsigned long)df->out.udf - (unsigned long)df);
		if (0 == fa->state.notend) {
			umem_info uinfo;
			/* def value */
			uinfo.buf = NULL;
			uinfo.size = 0;
			uinfo.dtype = 0;
			uinfo.is_end = 1;
			uinfo.shm_buf = df;
			if ((df->flg&(FUNC_FLAG_NEXT_DATA))) {
				DP_ERR("func mid:fid:name= %d:%d:%s, should not get next data\n", mid, fid, fa->name);
				df->out.ret = -1;
				fa->state.notend = 0;
				fa->state.pos = NULL;
				memset(&fa->state.uinfo, 0, sizeof(uinfo));
				return -1;
			}
			ret = fa->cb_umem(&uinfo, &fa->pri);
			if (-1 == ret) {
				DP_ERR("func mid:fid:name= %d:%d:%s\n", mid, fid, fa->name);
				df->out.ret = -1;
				return -1;
			}
			if (uinfo.size <= max) {
				df->flg = (uinfo.is_end)? df->flg|(FUNC_FLAG_END):df->flg&(~FUNC_FLAG_END);
				df->out.ret = 0;
				df->out.type = uinfo.dtype;
				df->out.size = uinfo.size;
				memcpy(df->out.udf, uinfo.buf, uinfo.size);
				memset(&fa->state.uinfo, 0, sizeof(uinfo));
				/* free umem */
				if (NULL != fa->cb_umem_end) {
					fa->cb_umem_end(&fa->pri);
				}
				DP_INFO(" size = %d\n", df->out.size);
			} else {
				df->flg = df->flg&(~FUNC_FLAG_END);
				df->out.ret = 0;
				df->out.type = uinfo.dtype;
				df->out.size = max;
				memcpy(df->out.udf, uinfo.buf, max);

				funcs[mid][fid].state.notend = 1;
				funcs[mid][fid].state.pos = uinfo.buf + max;
				memcpy(&fa->state.uinfo, &uinfo, sizeof(uinfo));
				DP_INFO(" size = %d ret = %d\n", df->out.size, df->out.ret);
			}
		} else {
			umem_info *ui = &fa->state.uinfo;
			int left = fa->state.uinfo.size-(fa->state.pos-fa->state.uinfo.buf);
			if (!(df->flg&(FUNC_FLAG_NEXT_DATA))) {
				DP_ERR("func mid:fid:name= %d:%d:%s, should get next data\n", mid, fid, fa->name);
				df->out.ret = -1;
				fa->state.notend = 0;
				fa->state.pos = NULL;
				memset(&fa->state.uinfo, 0, sizeof(ui));
				/* free umem */
				if (NULL != fa->cb_umem_end) {
					fa->cb_umem_end(&fa->pri);
				}
				return -1;
			}
			if (left <= max) {
				df->flg = (ui->is_end)? df->flg|(FUNC_FLAG_END):df->flg&(~FUNC_FLAG_END);
				df->out.ret = 0;
				df->out.type = ui->dtype;
				df->out.size = left;
				memcpy(df->out.udf, fa->state.pos, left);
				fa->state.notend = 0;
				fa->state.pos = NULL;
				memset(&fa->state.uinfo, 0, sizeof(ui));
				/* free umem */
				if (NULL != fa->cb_umem_end) {
					fa->cb_umem_end(&fa->pri);
				}
				DP_INFO(" size = %d\n", df->out.size);
			} else {
				df->flg = df->flg&(~FUNC_FLAG_END);
				df->out.ret = 0;
				df->out.type = ui->dtype;
				df->out.size = max;
				memcpy(df->out.udf, fa->state.pos, max);
				fa->state.notend = 1;
				fa->state.pos += max;
				DP_INFO(" size = %d\n", df->out.size);
			}

		}
	}
	return 0;
}

int DsystemInit(void)
{
	return func_init();
}

int DsystemExit(void)
{
	func_deinit();
	return 0;
}
